package com.ls.fw.mvc.springmvc.support.interceptor;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.ModelAndView;

import com.ls.fw.commons.core.utils.collections.CollectionUtils;
import com.ls.fw.web.core.servlet.http.util.IPAddress;
import com.ls.fw.web.core.servlet.http.util.IPRange;
import com.ls.fw.web.core.servlet.utils.HttpUtils;
import com.ls.fw.web.core.servlet.utils.ObjectUtil;


/**
 * 访问拦截器：
 * excludedUrl:
 * includedUrl:
 * deny优先于allow，如果在deny列表中，就算在allow列表中，也会被拒绝。
	        如果allow没有配置或者为空，则允许所有访问
	配置的格式
		  IP
		  或者
		  IP/SUB_NET_MASK_size
		其中
		  128.242.127.1/24
		24表示，前面24位是子网掩码，比对的时候，前面24位相同就匹配。
		如：128.242.127.1/24,128.242.128.1
 * @author lisheng
 * @date 2016年1月22日 下午8:27:52
 * @version V1.0
 */
public class AccessInterceptor extends BaseInterceptor implements InitializingBean{

	public static final String PARAM_NAME_ALLOW = "allow";
	public static final String PARAM_NAME_DENY = "deny";
	/**
	 * 不包含的连接
	 */
	protected List<String> excludedUrl = null;

	/**
	 * 包含的连接
	 */
	protected List<String> includedUrl = null;
	
	/**
	 * 允许访问的地址
	 */
	protected String allow = "";

	/**
	 * 不允许访问的地址
	 */
	protected String deny = "";
	 
	// no need to inject it for now..
    private PathMatcher pathMatcher = new AntPathMatcher();


	protected List<IPRange> allowList = new ArrayList<IPRange>();
	protected List<IPRange> denyList = new ArrayList<IPRange>();

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) throws Exception {
		
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView modelAndView) throws Exception {
			
	}

	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}
		   
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		 boolean ret = true;
//		 System.out.println(request.getRemoteAddr());
//		 System.out.println(request.getRemoteHost());
//		 System.out.println(getIpAddress(request));
		 if (open) {
			 ret = false;
			 if (isPermittedRequest(request)) {
				 String path = request.getRequestURI();
				 if(this.isInValidUrl(path)){
					 ret = false;
					logger.info("--deny url:" + path);
				 }else{
					 if(this.isValidUrl(path)){
						 ret = true;
					 }else{
						logger.info("--deny url:" + path);
					 }
				 }
			 }else{
				 logger.info("--deny ip:" + HttpUtils.getIp(request));
				 ret = false;
			 }
		 }
		return ret;
	}

	/**
	 * 是否为允许的连接
	 * 
	 * @author lisheng
	 * @date 2016年1月22日 下午8:14:31
	 * @version V1.0
	 * @param path
	 * @return
	 */
	protected boolean isValidUrl(String path) {
		if(CollectionUtils.isEmpty(includedUrl)){
			return true;
		}
		return CollectionUtils.isEmpty(this.includedUrl)
				||this.isExist(this.includedUrl, path);
	}

	
	/**
	 * 是否为无效的连接
	 * 
	 * @author lisheng
	 * @date 2016年1月22日 下午8:15:00
	 * @version V1.0
	 * @param path
	 * @return
	 */
	protected boolean isInValidUrl(String path) {
		return CollectionUtils.isNotEmpty(this.includedUrl)
				&&this.isExist(excludedUrl, path);
	}
	
	protected void initAllow(String allow){
		allowList.clear();
		String param = allow;
		if (ObjectUtil.isNotEmpty(param)) {
			param = param.trim();
			String[] items = param.split(",");

			for (String item : items) {
				if (ObjectUtil.isEmpty(item)) {
					continue;
				}

				IPRange ipRange = new IPRange(item);
				allowList.add(ipRange);
			}
		}
		logger.info("allowList:" + allowList);
	}
	
	
	protected void initDeny(String _deny){
		denyList.clear();
		String deny = _deny;
		if (ObjectUtil.isNotEmpty(deny)) {
			deny = deny.trim();
			String[] items = deny.split(",");

			for (String item : items) {
				if (ObjectUtil.isEmpty(item)) {
					continue;
				}

				IPRange ipRange = new IPRange(item);
				denyList.add(ipRange);
			}
		}
		logger.info("denyList:" + denyList);
	}

	/**
	 * 是否是允许访问的请求
	 * 
	 * @author Defender 2014年2月16日 下午12:03:32
	 * @param request
	 * @return
	 */
	protected boolean isPermittedRequest(HttpServletRequest request) {
		String remoteAddress = HttpUtils.getIp(request);
		try {
			return isPermittedRequest(remoteAddress);
		} catch (Exception e) {
			this.logger.error(e.getMessage(), e);
			return true;
		}
	}

	/**
	 * 是否是允许访问的ip
	 * 
	 * @author Defender 2014年2月16日 下午12:03:04
	 * @param remoteAddress
	 * @return
	 */
	protected boolean isPermittedRequest(String remoteAddress) {
		logger.debug("remoteAddress:" + remoteAddress);
		boolean isPermitted = false;
		if ("127.0.0.1".equals(remoteAddress)) {
			return true;
		}
		boolean ipV6 = remoteAddress != null
				&& remoteAddress.indexOf(':') != -1;
		if (ipV6) {
			if ("0:0:0:0:0:0:0:1".equals(remoteAddress)) {
				isPermitted = true;
			}else{
				if (CollectionUtils.isEmpty(denyList) 
					&& CollectionUtils.isEmpty(allowList)) {
					isPermitted = true;
				}
			}
			return isPermitted;
		}else{
			boolean existDeny = false;
			IPAddress ipAddress = new IPAddress(remoteAddress);
			if (CollectionUtils.isNotEmpty(denyList)) {
					isPermitted = false;
					for (IPRange range : denyList) {
						if (range.isIPAddressInRange(ipAddress)) {
							isPermitted =  false;
							existDeny = true;
							break;
						}
					}
			}
			if(!existDeny){
				isPermitted = true;
				if (CollectionUtils.isNotEmpty(allowList)) {
					isPermitted = false;
					for (IPRange range : allowList) {
						if (range.isIPAddressInRange(ipAddress)) {
							isPermitted = true;
							break;
						}
					}
				}
			}
		}
		return isPermitted;
	}
	  
	protected boolean isExist(List<String> list, String path) {
    	boolean exist = false;
		if(CollectionUtils.isNotEmpty(list)){
	        for (String pattern : list) {
	            if (pathMatcher.match(pattern, path)) {
	            	exist = true;
	            	break;
	            }
	        }
	    }
        return exist;
    }

	public PathMatcher getPathMatcher() {
		return this.pathMatcher;
	}

	public void setPathMatcher(PathMatcher pathMatcher) {
		this.pathMatcher = pathMatcher;
	}

	public String getAllow() {
		return this.allow;
	}

	public void setAllow(String allow) {
		this.allow = allow;
	}

	public String getDeny() {
		return this.deny;
	}

	public void setDeny(String deny) {
		this.deny = deny;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		this.initAllow(deny);
		this.initAllow(allow);
	}
}
